using System;
using System.Collections;

namespace Jeffrey.XFramework
{
    public sealed class ProcessorChain : IEnumerable
    {
        public enum ProcessorChainName
        {
            ProcessorChain,
            PreFetchChain,
            FetchChain,
            PostFetchChain,
            ExtractChain,
            StoreChain
        }

        public ProcessorChain(ProcessorChainName name)
            :this(null, name){ }
        public ProcessorChain(Processor firstProcessor, ProcessorChainName name)
        {
            m_FirstProcessor = m_LastProcessor = firstProcessor;
            if (firstProcessor != null)
            {
                firstProcessor.NextProcessor = null;
                firstProcessor.PreProcessor  = null;
                m_Count = 1;
            }
            else
                m_Count = 0;

            m_NextProcessorChain = null;
            m_Name = name;
        }

        #region implelement foreach

        private class ProcessorChainEnumerator : IEnumerator
        {
            internal ProcessorChainEnumerator(ProcessorChain pc)
            {
                _start  = false;
                m_chain = pc;
                _chain  = pc;
            }

            Boolean IEnumerator.MoveNext()
            {
                if (!_start)
                {
                    _start = true;
                    _pro   = _chain.FirstProcessor;
                }
                else
                    _pro = _pro.NextProcessor;

                while (_pro == null)
                {
                    _chain = _chain.NextProcessorChain;
                    if (_chain == null)
                        return false;

                    _pro = _chain.FirstProcessor;
                }

                return true;
            }

            void IEnumerator.Reset()
            {
                _start = false;
                _chain = m_chain;
            }

            Object IEnumerator.Current
            {
                get { return _pro; }
            }

            private Boolean   _start;
            private Processor _pro;
            private ProcessorChain _chain;
            private ProcessorChain m_chain;

        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new ProcessorChainEnumerator(this);
        }

        #endregion

        public void AddProcessor(Processor processor)
        {
            if (processor == null)
                return;

            if (m_LastProcessor != null)
            {
                m_LastProcessor.NextProcessor = processor;
            }
            else
            {
                m_FirstProcessor = processor;
            }
            processor.PreProcessor = m_LastProcessor;
            m_LastProcessor = processor;
            m_LastProcessor.NextProcessor = null;

            m_Count++;
        }

        public void ClearProcessors()
        {
            m_FirstProcessor = m_LastProcessor = null;
            m_Count = 0;
        }

        public void DeleteProcessor(Processor p)
        {
            if (p == null)
                return;

            Processor p1 = this.m_FirstProcessor;

            while (p1 != null)
            {
                if (ReferenceEquals(p1, p))
                {
                    if (p1.PreProcessor == null)
                        m_FirstProcessor = p1.NextProcessor;
                    else
                        p1.PreProcessor.NextProcessor = p1.NextProcessor;

                    if (p1.NextProcessor == null)
                        m_LastProcessor = p1.PreProcessor;
                    else
                        p1.NextProcessor.PreProcessor = p1.PreProcessor;

                    return;
                }
                p1 = p1.NextProcessor;
            }
        }

        public ProcessorChain NextProcessorChain
        {
            get { return m_NextProcessorChain; }
            set { m_NextProcessorChain = value; }
        }
        public Processor FirstProcessor
        {
            get { return m_FirstProcessor; }
        }
        public Int32 Count
        {
            get { return m_Count; }
        }
        public ProcessorChainName Name
        {
            get { return m_Name; }
        }

        private Int32          m_Count;
        private Processor      m_FirstProcessor;
        private Processor      m_LastProcessor;
        private ProcessorChain m_NextProcessorChain;

        private ProcessorChainName m_Name;
    }
}
